package reading.common.domain;


import com.google.common.collect.Sets;
import reading.common.exception.HlPrivilegeAuthException;
import reading.common.exception.HlUnauthorizedException;
import reading.util.utils.TimeUtils;

import java.util.Collection;
import java.util.Optional;
import java.util.Set;

/**
 * Auth Token
 * Immutable对象，当前提供 copyOnTimestamp() 函数来复制并重置创建时间戳
 *
 * @author yangbajing(yangbajing @ gmail.com) on 2016-09-08.
 * @author txw
 */
public class AuthToken {
    private static final int TOKEN_ITEM_LEN = 5;

    private static ThreadLocal<AuthToken> authTokenThreadLocal = new ThreadLocal<>();

    /**
     * 登录用户ID
     */
    public final Long ownerId;

    /**
     * 单位（秒），token创建时时间戳
     */
    public final Long timestamp;

    /**
     * 登录用户源IP
     */
    public final String ip;

    /**
     * 登录用户角色
     */
    public final Set<Long> roles;

    public final String weChatId;

    public final String userName;

    public final String email;

    public final String phone;

    public final String qq;

    public AuthToken(Long ownerId, String wechat, Long timestamp, String ip, Set<Long> roles, String userName, String email, String phone, String qq) {
        this.ownerId = ownerId;
        this.weChatId = wechat;
        this.timestamp = timestamp;
        this.ip = ip;
        this.roles = roles;
        this.userName = userName;
        this.email = email;
        this.phone = phone;
        this.qq = qq;
    }

    /**
     * 创建AutoTOken
     *
     * @param ownerId 登录ID
     * @param ip      用户访问源IP
     * @param roles   用户角色列表
     * @return 返回新创建 AuthToken
     */
    static public AuthToken create(Long ownerId, String wechat, String ip, Collection<Long> roles, String userName, String email, String phone, String qq,Long timestamp) {
        return new AuthToken(ownerId, wechat, timestamp, ip, Sets.newHashSet(roles), userName, email, phone, qq);
    }


    /**
     * 从ThreadLocal中获取AuthToken实例
     *
     * @return 返回AuthToken的Optional包装对象
     */
    public static Optional<AuthToken> getFromThreadLocal() {
        return Optional.ofNullable(authTokenThreadLocal.get());
    }

    /**
     * 从ThreadLocal中获取或设置AuthToken
     *
     * @param token AuthToken实例
     * @return 当ThreadLocal中为空是，将token存入并返回；否则直接返回ThreadLocal中已存在的
     */
    public static AuthToken getAndSetFromThreadLocal(AuthToken token) {
        AuthToken authToken = authTokenThreadLocal.get();
        if (authToken == null) {
            authTokenThreadLocal.set(token);
            authToken = token;
        }
        return authToken;
    }

    /**
     * 从ThreadLocal中删除AuthToken实例
     **/
    public static void removeOnThreadLocal() {
        authTokenThreadLocal.remove();
    }

    @Override
    public String toString() {
        return Long.toString(ownerId) +
                ";" +
                weChatId +
                ";" +
                timestamp +
                ";" +
                ip +
                ";" +
                roles.stream().map(i -> Long.toString(i)).reduce((x, y) -> x + "," + y).orElse("");
    }

    /**
     * 复制并重置创建时间戳
     *
     * @return 新AuthToken实例
     */
    public AuthToken copyOnTimestamp() {
        return new AuthToken(this.ownerId, this.weChatId, TimeUtils.nowSeconds(), this.ip, this.roles, userName, email, phone, qq);
    }

    public void validateForRole(long roleId) {
        if (!AuthToken.getFromThreadLocal().isPresent()) {
            throw new HlUnauthorizedException("需要登录");
        }
        AuthToken token = AuthToken.getFromThreadLocal().get();
        if (!token.roles.contains(roleId)) {
            throw new HlPrivilegeAuthException(403, "需要管理员权限");
        }
    }

}
